package cn.initcap.algorithm.swing.sort.insertion;

import cn.initcap.algorithm.swing.AlgoVisHelper;
import cn.initcap.algorithm.swing.BaseAlgoFrame;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;

/**
 * @author initcap
 * @date 8/1/19 7:18 PM
 */
public class AlgoVisualizer {

    private static int DELAY = 40;
    private InsertionSortData data;
    private BaseAlgoFrame frame;

    public AlgoVisualizer(int sceneWidth, int sceneHeight, int n, InsertionSortData.Type dataType) {

        // 初始化数据
        data = new InsertionSortData(n, sceneHeight, dataType);

        // 初始化视图
        EventQueue.invokeLater(() -> {
            frame = new BaseAlgoFrame("Insertion Sort Visualization", sceneWidth, sceneHeight) {
                @Override
                public void draw(Graphics graphics) {
                    int w = sceneWidth / data.N();
                    for (int i = 0; i < data.N(); i++) {
                        Graphics2D g2d = (Graphics2D) graphics;
                        if (i < data.orderedIndex) {
                            AlgoVisHelper.setColor(g2d, AlgoVisHelper.RED);
                        } else {
                            AlgoVisHelper.setColor(g2d, AlgoVisHelper.GREY);
                        }

                        if (i == data.currentIndex) {
                            AlgoVisHelper.setColor(g2d, AlgoVisHelper.LIGHT_BLUE);
                        }
                        AlgoVisHelper.fillRectangle(g2d, i * w, sceneHeight - data.get(i), w - 1, data.get(i));
                    }
                }
            };

            new Thread(() -> {
                run();
            }).start();
        });
    }

    public AlgoVisualizer(int sceneWidth, int sceneHeight, int n) {
        this(sceneWidth, sceneHeight, n, InsertionSortData.Type.Default);
    }

    public static void main(String[] args) {

        int sceneWidth = 800;
        int sceneHeight = 800;
        int n = 100;

        new AlgoVisualizer(sceneWidth, sceneHeight, n, InsertionSortData.Type.NearlyOrdered);
    }

    public void run() {

        setData(0, -1);

        for (int i = 0; i < data.N(); i++) {

            setData(i, i);
            for (int j = i; j > 0 && data.get(j) < data.get(j - 1); j--) {
                data.swap(j, j - 1);
                setData(i + 1, j - 1);
            }
        }
        this.setData(data.N(), -1);

    }

    private void setData(int orderedIndex, int currentIndex) {
        data.orderedIndex = orderedIndex;
        data.currentIndex = currentIndex;

        frame.render(data);
        AlgoVisHelper.pause(DELAY);
    }
}